unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;

type
  TService1 = class(TService)
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceCreate(Sender: TObject);
  private
    { Private declarations }
    FStartCommand: string;
    FStopCommand: string;
    FDependencies: string;
    FDisplayName: string;
    FServiceName: string;
    FWorkPath: string;
  private
    function ExecuteCommand(const cmd: string): boolean;
    function GetCommandPath(const cmd: string): string;
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;

var
  Service1: TService1;

implementation
uses IniFiles, StrUtils;
{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;

function TService1.ExecuteCommand(const cmd: string): boolean;
var si: TStartupInfo;
    pi: TProcessInformation;
    s: string;
    pPath: pchar;
begin
  s := Trim(cmd);
  result := Length(s)>0;
  if result then
  begin
    ZeroMemory(@si, sizeof(si));
    si.cb := SizeOf(TStartupInfo);
    si.dwFlags := STARTF_USESHOWWINDOW;
    si.wShowWindow := SW_HIDE;
    if FWorkPath='' then pPath := nil
    else pPath := pchar(FWorkPath);
    result := CreateProcess(nil, pchar(s), nil,nil,False,CREATE_NEW_CONSOLE,nil,pPath,si,pi);
    if result then
    begin
      CloseHandle(pi.hProcess);
      CloseHandle(pi.hThread);
    end;
  end;
end;

function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  if FStartCommand<>'' then
  begin
    FWorkPath := GetCommandPath(FStartCommand);
    Started := ExecuteCommand(FStartCommand);
  end else
    Started := False;
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  if FStopCommand<>'' then
  begin
    FWorkPath := GetCommandPath(FStopCommand);
    Stopped := ExecuteCommand(FStopCommand);
  end else
    Stopped := False;
end;

procedure TService1.ServiceCreate(Sender: TObject);
var buf: array[0..MAX_PATH] of char;
    inif: TIniFile;
    s: string;
begin
  if GetModuleFileName(0,buf,MAX_PATH)>0 then
  begin
    s := ChangeFileExt(StrPas(buf),'.ini');
    if FileExists(s) then
    begin
      inif := TIniFile.Create(s);
      try
        FStartCommand := Trim(inif.ReadString('Service','StartCommand',''));
        FStopCommand := Trim(inif.ReadString('Service','StopCommand',''));
        FDependencies := Trim(inif.ReadString('Service','Dependencies',''));
        FDisplayName := Trim(inif.ReadString('Service', 'DisplayName',''));
        FServiceName := Trim(inif.ReadString('Service','ServiceName',''));
      finally
        inif.Free;
      end;
      if length(Trim(FServiceName))>0 then
        Name := Trim(FServiceName);
      DisplayName := FDisplayName;
//      if Length(FDependencies)>0 then Dependencies
    end;
  end;
end;

function TService1.GetCommandPath(const cmd: string): string;
var s: string;
    k: integer;
begin
  result := '';
  if cmd[1]='"' then
  begin
    k := PosEx('"',cmd,2);
    if k>0 then
    begin
      s := Copy(cmd,2,k-2);
      if FileExists(s) then result := ExtractFilePath(s);
    end;
  end else
  begin
    k := Pos(' ',cmd);
    if k>0 then s := Copy(cmd,1,k-1)
    else s := cmd;
    if FileExists(s) then result := ExtractFilePath(s);
  end;
end;

end.
